/*
 * Chastoslov
 * Copyright (C) 2009 Alexandr Stroghov
 * 
 * stroghov@gmail.com
 * 
 * This program is free software; you can redistribute it and/or modify it under the terms of the 
 * GNU General Public License, version 2, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this program; if 
 * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
 * MA 02111-1307 USA
*/
package world.ah.wf.guiclient;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.sql.PreparedStatement;
import java.util.Properties;

/** 
 * Предоставляет дополнительные возможности для работы с соединением 
 */
public class ConnectionAssistant {
  // Собственно соединение 
  private Connection conn = null;
  public void setConn(Connection conn) {this.conn = conn;}
  public Connection getConn() {return conn;}
  // Состояние подключения 
  private boolean connected = false;
  public void setConnected(boolean connected) {this.connected = connected;}
  public boolean getConnected() {return connected;}
  // Класс JDBC драйвера 
  private String connDriver = "org.apache.derby.jdbc.EmbeddedDriver";
  public void setConnDriver(String connDriver) {this.connDriver = connDriver;}
  public String getConnDriver() {return connDriver;}
  // URL соединения 
  private String connURL = "jdbc:derby:wfdb";
  public void setConnURL(String connURL) {this.connURL = connURL;}
  public String getConnURL() {return connURL;}
  // Схема 
  private String schema = "WF"; 
  public void setSchema(String schema) {this.schema = schema;}
  public String getSchema() {return schema;}
  // Имя пользователя БД
  private String userName = "wf"; 
  public void setUserName(String userName) {
    userName = userName.trim();
    userName = userName.toLowerCase();
    this.userName = userName;
  }
  public String getUserName() {return userName;}
  // Имя читателя
  private String readerName = "";
  public String getReaderName() {return readerName;}
  public void setReaderName(String readerName) {this.readerName = readerName;}
  // Пароль 
  private char[] password = "wf".toCharArray(); 
  public void setPassword(char[] password) {this.password = General.encryptCharArray(password);}
  public char[] getPassword() {
    if(this.getRememberPassword()) return General.decryptCharArray(password);
    else return new char[0];
  }
  // Запомнить пароль
  private boolean rememberPassword = false;
  public void setRememberPassword(boolean rememberPassword) {
    this.rememberPassword = rememberPassword;}
  public boolean getRememberPassword() {return rememberPassword;}
  // Подключаться при старте 
  private boolean autoConnect = false;
  public void setAutoConnect(boolean autoConnect) {this.autoConnect = autoConnect;}
  public boolean getAutoConnect() {return autoConnect;}
  // Имя файла параметров 
  private String propertiesFileName;
  public void setPropertiesFileName(String propertiesFileName) {this.propertiesFileName = propertiesFileName;}
  public String getPropertiesFileName() {return propertiesFileName;}
  // Загружает параметры из файла 
  public void loadProperties() throws Exception {
    if(propertiesFileName.length() < 1) throw new Exception("Properties file name not defined");
    Properties prop = new Properties();
    prop.load(new FileInputStream(this.propertiesFileName));
    //
    String s;
    this.setConnDriver(prop.getProperty("connDriver", ""));
    this.setConnURL(prop.getProperty("connURL", ""));
    this.setSchema(prop.getProperty("schema", ""));
    this.setUserName(prop.getProperty("userName", ""));
    s = prop.getProperty("rememberPassword", "false");    
    this.setRememberPassword(new Boolean(s).booleanValue());
    if(this.getRememberPassword()) 
      this.password = prop.getProperty("password", "").toCharArray();
    s = prop.getProperty("autoConnect", "false");
    this.setAutoConnect(new Boolean(s).booleanValue());
  };
  // Сохраняет параметры в файл 
  public void saveProperties() throws Exception {
    Properties prop = new Properties();
    prop.setProperty("connDriver", this.getConnDriver());
    prop.setProperty("connURL", this.getConnURL());
    prop.setProperty("schema", this.getSchema());
    prop.setProperty("userName", this.getUserName());
    prop.setProperty("rememberPassword", Boolean.toString(this.getRememberPassword()));
    if(this.getRememberPassword()) prop.setProperty("password", String.valueOf(password));
    prop.setProperty("autoConnect", Boolean.toString(this.getAutoConnect()));
    prop.store(new FileOutputStream(this.propertiesFileName), "Connection properties");
  };
  /**
   * Запускается при подключении и отключении
   * @param connected состояние (подключено/отключено)
   */
  public void connectedChanged(boolean connected) {}
  public void readerNameChanged() {}
  /**
   * Устанавливает соединение и определяет схему по умолчанию
   * @throws java.lang.Exception
   */
  public void connect() throws Exception {
    if(connected) return;
    Class dr = Class.forName(getConnDriver());
    if(connURL.toLowerCase().matches(".*;[\\s]*user[\\s]*=.*") ||
       connURL.toLowerCase().matches(".*;[\\s]*password[\\s]*=.*")
      ) throw new Exception("User name and password must not be specified in the connection URL.");
    if(userName.length() < 1) throw new Exception("Имя пользователя не указано.");
    char[] pwd = General.decryptCharArray(password);
    if(pwd.length < 1) throw new Exception("Пароль не задан.");
    //System.out.println(getConnURL() + ";user=" + userName + ";password=" + String.valueOf(pwd));
    
    /*setConn(DriverManager.getConnection(getConnURL() + ";user=" + userName + ";password=" + 
      String.valueOf(pwd)));*/
    
    setConn(DriverManager.getConnection(getConnURL(), userName, String.valueOf(pwd)));
    Arrays.fill(pwd, '*');

    if(!this.getRememberPassword()) Arrays.fill(password, '*');
    // Установка текущей схемы 
    try {
      PreparedStatement prst = getConn().prepareStatement("set schema ?"); 
      prst.setString(1, getSchema());
      prst.executeUpdate();
    } catch (Exception ex) {getConn().close(); throw ex;}
    // Проверка пользователя 
    try {findOutReaderName();} 
    catch (Exception ex) {getConn().close(); throw ex;}
    //
    setConnected(true);
    connectedChanged(getConnected());
  }
  /**
   * Узнает имя текущего читателя
   * @throws java.sql.SQLException
   */
  private void findOutReaderName() throws Exception {
    Statement st = getConn().createStatement(ResultSet.TYPE_FORWARD_ONLY, 
      ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
    ResultSet rs;
    rs = st.executeQuery("select NAME from READER where CODE = user");
    if(rs.next()) readerName = rs.getString(1);
    else throw new Exception("Пользователь '" + userName + "' не зарегистрирован в программе");
    rs.close();
    readerNameChanged();
  }
  /**
   * Разрывает соединение
   * @throws java.lang.Exception
   */
  public void disconnect() throws Exception {
    if(!connected) return;
    setConnected(false);
    readerName = "";
    getConn().close(); 
    //readerNameChanged();
    connectedChanged(getConnected());
  }




 
  
  
}
